/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.web.core.jsploader; import java.util.Set; import java.util.Iterator; import java.util.Comparator; import java.util.Collection; import java.util.ArrayList; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.io.ObjectInputStream; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.NotActiveException; import java.io.FileNotFoundException; import java.io.File; import javax.swing.text.StyledDocument; import javax.swing.text.BadLocationException; import javax.servlet.ServletContext; import org.openide.*; import org.openide.cookies.EditorCookie; import org.openide.cookies.CompilerCookie; import org.openide.cookies.SaveCookie; import org.openide.filesystems.*; import org.openide.loaders.*; import org.openide.windows.*; import org.openide.actions.OpenAction; import org.openide.actions.ViewAction; import org.openide.text.*; import org.openide.util.*; import org.openide.util.actions.*; import org.openide.nodes.Node; import org.openide.nodes.Children; import org.openide.nodes.AbstractNode; import org.openide.nodes.NodeListener; import org.openide.compiler.Compiler; import org.openide.compiler.CompilerJob; import org.openide.compiler.CompilerType; import org.netbeans.modules.java.JavaDataObject; import org.netbeans.modules.java.JavaCompilerType; import com.sun.jsp.compiler.Main; import com.sun.jsp.compiler.ClassName; import com.sun.jsp.compiler.JspReader; import com.sun.jsp.JspException; /** Object that provides main functionality for internet data loader. * This class is final only for performance reasons, * can be unfinaled if desired. * * @author Petr Jiricka */ public final class JspDataObject extends MultiDataObject { // public static final String PROP_SERVLET_DATAOBJECT = "servlet_do"; // NOI18N public static final String PROP_COMPILATION_FINISHED = "jsp_compilation_finished"; // NOI18N public static final String PROP_SERVLET_GENERATED = "jsp_servlet_generated"; // NOI18N public static final String EA_JSP_ERRORPAGE = "jsp_errorpage"; // NOI18N transient protected Main.ClassFileData classFileData = null; transient protected JspServletEditor servletEdit; transient protected JspServletDataObject servletDataObject; public JspDataObject (FileObject pf, final UniFileLoader l) throws DataObjectExistsException { super (pf, l); initialize(); } protected org.openide.nodes.Node createNodeDelegate () { return new JspNode (this); } /** Creates a compiler and adds it into the job: for beans on which this JSP depends, * generating servlet for this JSP, for compiling this JSP * into a servlet, for other JSPs used by this JSP by <jsp:include> and <jsp:forward>. */ protected void createCompiler(CompilerJob job, java.lang.Class type, /*Compiler.Depth depth,*/ boolean individual) { // clean compiler, if any Compiler cleanCompiler = null; // check if we should clean first if (type == JspCompiler.CLEAN || type == JspCompiler.BUILD) { // construct clean compiler cleanCompiler = new CleanCompiler(this); if (type == JspCompiler.CLEAN) { job.add(cleanCompiler); return; } } // the real type Class jspType = individual ? JspCompiler.BUILD : type; if (jspType == JspCompiler.CLEAN) jspType = JspCompiler.BUILD; try { // save first SaveCookie sc = (SaveCookie)getCookie(SaveCookie.class); if (sc != null) sc.save(); // create the compiler for this page JspCompiler jspCompiler = new JspCompiler(this, jspType); if (cleanCompiler != null) jspCompiler.dependsOn(cleanCompiler); // check if this compiler has already been added Collection compilers = job.compilers(); for (Iterator it = compilers.iterator(); it.hasNext(); ) { Object other = it.next(); if (jspCompiler.equals(other)) { JspCompiler otherJspComp = (JspCompiler)other; // make the cookies consistent if (jspCompiler.getType () != otherJspComp.getType()) { otherJspComp.setType(JspCompiler.BUILD); } // make the dependencies consistent - it's enough to depend on the cleancompiler otherJspComp.dependsOn(jspCompiler.dependsOn()); return; } } // get the JspCompilationInfo JspReader reader = JspReader.createJspReader(JspCompileUtil.getFileObjectFileName( getPrimaryFile())); JspInfo jspInfo = JspCompileUtil.analyzePage(reader, getPrimaryFile()); JspCompilationInfo compInfo = new JspCompilationInfo(jspInfo, getPrimaryFile()); // acquire compilers for the beans DataObject beans[] = compInfo.getBeans(); CompilerJob beansJob = new CompilerJob(Compiler.DEPTH_ZERO); for (int i = 0; i < beans.length; i++) { CompilerCookie c = (CompilerCookie)beans[i].getCookie(CompilerCookie.Compile.class); if (c != null) { c.addToJob(beansJob, Compiler.DEPTH_ZERO); } else { } } // now refresh the folders CompilerJob refreshBeansJob = new CompilerJob(Compiler.DEPTH_ZERO); RefreshCompiler rc; for (int i = 0; i < beans.length; i++) { rc = new RefreshCompiler(beans[i].getPrimaryFile().getParent()); rc.dependsOn(beansJob); refreshBeansJob.add(rc); } // add it, add dependencies, error page info jspCompiler.setErrorPage(compInfo.isErrorPage()); jspCompiler.dependsOn (refreshBeansJob); job.add(jspCompiler); // add the compiler for the generated servlet JavaCompilerType.IndirectCompiler servletComp = getServletCompiler(CompilerCookie.Build.class); if (servletComp == null) { Compiler error = new ErrorCompiler(getPrimaryFile(), new Exception( NbBundle.getBundle(JspDataObject.class).getString("CTL_BadCompilerType")), true); job.add(error); } else { // compile the servlet servletComp.dependsOn(jspCompiler); jspCompiler.servletCompiler = servletComp; job.add(servletComp); // rename the class Compiler ren = new RenameCompiler(jspCompiler); ren.dependsOn(servletComp); job.add(ren); // refresh the folder Compiler refr = new RefreshCompiler(JspCompileUtil.getContextOutputRoot(getPrimaryFile())); refr.dependsOn(ren); job.add(refr); } // add compilers for referenced pages - jsp:include and jsp:forward JspDataObject usedPages[] = compInfo.getReferencedPages(); for (int i = 0; i < usedPages.length; i++) { JspDataObject jspdo = usedPages[i]; jspdo.createCompiler(job, CompilerCookie.Compile.class, /*depth,*/ false); } // add compilers for error pages JspDataObject errorPage[] = compInfo.getErrorPage(); for (int i = 0; i < errorPage.length; i++) { JspDataObject jspdo = errorPage[i]; jspdo.createCompiler(job, CompilerCookie.Compile.class, /*depth,*/ false); } } catch (JspException e) { Compiler error = new ErrorCompiler(getPrimaryFile(), e, false); job.add(error); } catch (FileStateInvalidException e) { Compiler error = new ErrorCompiler(getPrimaryFile(), e, true); job.add(error); } catch (IOException e) { Compiler error = new ErrorCompiler(getPrimaryFile(), e, false); job.add(error); } } public boolean isUpToDate() { if (getServletDataObject() == null) return false; FileObject clazz = getCorrespondingClass(true); if (clazz == null) return false; if (clazz.lastModified().compareTo(getPrimaryFile().lastModified()) < 0) return false; return true; } /** Return the compiler for the resulting servlet.*/ private JavaCompilerType.IndirectCompiler getServletCompiler(Class type) throws IOException { CompilerType ct = CompilerSupport.getCompilerType (getPrimaryEntry()); if (ct == null) { JspCompilerSupport ccookie = (JspCompilerSupport)getCookie(JspCompilerSupport.Compile.class); if (ccookie == null) return null; ct = ccookie.defaultCompilerType(); } if (ct instanceof JavaCompilerType) { JavaCompilerType.IndirectCompiler comp = ((JavaCompilerType)ct).prepareIndirectCompiler(type, null); return comp; } else { return null; } } /** Searches for the class file corresponding to this JSP. * Then checks whether the name of the actual class in the file matches this file's name.<br> * @return corresponding class file, if found, otherwise <code>null</code><br>*/ public FileObject getCorrespondingClass(boolean checkClassName) { FileObject classFo = getClassFile(); if (classFo == null || (!checkClassName)) return classFo; // make sure that the actual class in the class file, which may be different from // the class file name, matches this servlet's name. try { String classFileName = JspCompileUtil.getFileObjectFileName(classFo); String className = ClassName.getClassName(classFileName); if (className.equals(getClassFileData().getClassName())) return classFo; else return null; } catch (FileStateInvalidException e) { return null; } catch (JspException e) { return null; } } private FileObject getClassFile() { try { FileSystem outputFs = JspCompileUtil.getContextOutputRoot(getPrimaryFile()).getFileSystem(); if (getClassFileData() == null) return null; String cfn = getClassFileData().getClassFileName(); int index = cfn.lastIndexOf(File.separatorChar); if (index != -1) cfn = cfn.substring(index + 1); FileObject cl = outputFs.findResource(cfn); return cl; } catch (FileStateInvalidException e) { return null; } catch (IOException e) { return null; } } public Main.ClassFileData getClassFileData() { return classFileData; } public JspServletDataObject getServletDataObject() { return servletDataObject; } void compilationFinished() { firePropertyChange(PROP_COMPILATION_FINISHED, null, null); } void servletGenerated() { firePropertyChange(PROP_SERVLET_GENERATED, null, null); } private void initialize() { addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if (PROP_COMPILATION_FINISHED.equals(evt.getPropertyName())) updateClassFileData(); if (PROP_SERVLET_GENERATED.equals(evt.getPropertyName())) servletChanged(); } }); updateClassFileData(); servletChanged(); } /** Updates ClassFileData */ void updateClassFileData() { try { ServletContext context = new ServletContextImpl(getPrimaryFile().getFileSystem()); String realPath = context.getRealPath(getPrimaryFile().getPackageNameExt('/','.')); if (realPath == null) realPath = getPrimaryFile().getPackageNameExt('/','.'); // classfiledata classFileData = Main.getClassFileData( realPath, //JspCompileUtil.getFileObjectFileName(getPrimaryFile()), JspCompileUtil.getFileObjectFileName(JspCompileUtil.getContextOutputRoot(getPrimaryFile())), context.getRealPath("") // NOI18N //JspCompileUtil.getFileObjectFileName(JspCompileUtil.getContextRoot(getPrimaryFile())) ); } catch (Exception e) { classFileData = null; } } /** Updates classFileData, servletDataObject, servletEdit */ private void servletChanged() { // dataobject try { FileObject servletFileObject = updateServletFileObject(); if (servletFileObject != null) { // pending - maybe this slows down the compilation servletFileObject.refresh(true); DataObject dObj= TopManager.getDefault().getLoaderPool().findDataObject(servletFileObject); if (dObj instanceof JspServletDataObject) { servletDataObject = (JspServletDataObject)dObj; servletDataObject.setSourceJspPage(this); } } else servletDataObject = null; } catch (IOException e) { servletDataObject = null; } // editor RequestProcessor.postRequest(new Runnable() { public void run() { if (servletEdit != null) { if (servletDataObject == null) { removeServletEdit(); } else { boolean openAgain = servletEdit.isOpen(); removeServletEdit(); addServletEdit(); if (openAgain) servletEdit.open(); } } else { if (servletDataObject != null) { addServletEdit(); } } } }); } private void addServletEdit() { if (servletEdit == null) { servletEdit = (JspServletEditor)servletDataObject.getCookie(EditorCookie.class); getCookieSet().add(new ServletOpenCookie() { public void open() { servletEdit.open(); } }); } } private void removeServletEdit() { if (servletEdit != null) { servletEdit.close(); servletEdit = null; Node.Cookie open = getCookieSet().getCookie(ServletOpenCookie.class); if (open != null) getCookieSet().remove(open); } } /** Gets the current fileobject of the servlet corresponding to this JSP or null if may not exist. * Note that the file still doesn't need to exist, even if it's not null. */ private FileObject updateServletFileObject() throws IOException { if (classFileData == null) return null; File jspFile = new File(JspCompileUtil.getFileObjectFileName(getPrimaryFile())); jspFile.getPath(); FileObject contextRoot = JspCompileUtil.getContextOutputRoot(getPrimaryFile()); String pName = Main.getPackageName(jspFile); FileObject myFolder = contextRoot.getFileSystem().find(pName, null, null); if (myFolder == null) return null; myFolder.refresh(); FileObject servletFo; String s4 = JspCompileUtil.getClassNameSansNumberSansPackage(getPrimaryFile()); // NOI18N // first try the higher (new) number Main.ClassFileData newClassFileData = JspCompileUtil.cloneClassFileData(classFileData); newClassFileData.incrementNumber(); servletFo = myFolder.getFileObject(s4 + newClassFileData.getNumber(), "java"); // NOI18N if (servletFo != null) { return servletFo; } // then try the lower (old) number servletFo = myFolder.getFileObject(s4 + classFileData.getNumber(), "java"); // NOI18N return servletFo; } public interface ServletOpenCookie extends Node.Cookie { public void open(); } } /* * Log * 30 Gandalf 1.29 2/4/00 Petr Jiricka Fixed exception on * compilation for JSPs in jar files - bugs 5501, 5502 * 29 Gandalf 1.28 1/27/00 Petr Jiricka Changes in generating * names of the servlet * 28 Gandalf 1.27 1/17/00 Petr Jiricka Debug outputs removed * 27 Gandalf 1.26 1/17/00 Petr Jiricka * 26 Gandalf 1.25 1/16/00 Petr Jiricka Correct compilation * cookies. * 25 Gandalf 1.24 1/16/00 Petr Jiricka Duplicate checks etc. * 24 Gandalf 1.23 1/15/00 Petr Jiricka More fixes. * 23 Gandalf 1.22 1/15/00 Petr Jiricka Ensuring correct * compiler implementation - hashCode and equals * 22 Gandalf 1.21 1/14/00 Petr Jiricka Compilation fixes * 21 Gandalf 1.20 1/14/00 Petr Jiricka Generated servlet * refreshed after it has changed. * 20 Gandalf 1.19 1/13/00 Petr Jiricka More i18n * 19 Gandalf 1.18 1/12/00 Petr Jiricka i18n phase 1 * 18 Gandalf 1.17 1/10/00 Petr Jiricka Significant compilation * change - prepare compilers for Java beforehand. * 17 Gandalf 1.16 1/7/00 Petr Jiricka Bugfix - infinite loop * prevention for interdependent jsp:include-s * 16 Gandalf 1.15 1/6/00 Petr Jiricka Cleanup * 15 Gandalf 1.14 1/4/00 Petr Jiricka More bugfixes * 14 Gandalf 1.13 1/3/00 Petr Jiricka Added method for * acquiring generated class * 13 Gandalf 1.12 12/29/99 Petr Jiricka Added registration of * this page with the generated servlet * 12 Gandalf 1.11 12/29/99 Petr Jiricka Various compilation * fixes * 11 Gandalf 1.10 12/28/99 Petr Jiricka Compilation changes * 10 Gandalf 1.9 12/23/99 Jaroslav Tulach mergeInto deleted from * the CompilerJob. * 9 Gandalf 1.8 12/20/99 Petr Jiricka Checking in changes made * in the U.S. * 8 Gandalf 1.7 12/9/99 Petr Kuzel Overseas changes due * Tomcat 1.0.1 * 7 Gandalf 1.6 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 6 Gandalf 1.5 10/12/99 Petr Jiricka Removed debug messages * 5 Gandalf 1.4 10/10/99 Petr Jiricka Compiler creation * changes * 4 Gandalf 1.3 10/4/99 Petr Jiricka * 3 Gandalf 1.2 9/29/99 Petr Jiricka Compilation fixes * 2 Gandalf 1.1 9/27/99 Petr Jiricka Fixed creation of * ClassFileData * 1 Gandalf 1.0 9/22/99 Petr Jiricka * $ */